Namespace.Use("UI.Object", function(ns) {
    function BaseObject() {
        //
        //  Members.
        //
        var parent = null;
        var events = {};

        //
        //  Public methods.
        //
        this.GetHTMLElement = function() {
            throw "GetHTMLElement() should be overrided.";
        };
        this.Invalidate = function() {
            throw "Invalidate() should be overrided.";
        };
        this.IsOnDocument = function() {
            return document.contains(this.GetHTMLElement());
        };
        this.AccessParent = Polymorphic.Create(
            [],
            function() {
                return parent;
            },
            [BaseObject],
            function(new_parent) {
                if (this.IsOnDocument()) {
                    throw "Already on DOM.";
                }
                if (new_parent == this) {
                    throw "Cycling dependency.";
                }
                if (parent !== null && new_parent !== null) {
                    throw "Parent object can't be assigned.";
                }
                parent = new_parent;
            }
        );
        this.AccessPosition = function() {
            throw "AccessPosition() should be overrided.";
        };
        this.AccessSize = function() {
            throw "AccessSize() should be overrided.";
        };
        this.AccessVisibility = function() {
            throw "AccessVisibility() should be overrided.";
        };
        this.AccessLayer = function() {
            throw "AccessLayer() should be overrided.";
        };
        this.CalculateAbsolutePosition = function() {
            //  Initialize the counter.
            var total_x = 0, total_y = 0;

            //  Iterate from current object to the root object.
            var current = this;
            while(current !== null) {
                position = current.AccessPosition();
                total_x += position[0];
                total_y += position[1];
                current = current.AccessParent();
            }

            return [total_x, total_y];
        };
        this.RegisterEvent = Polymorphic.Create(
            [String, Function],
            function(event_name, callback) {
                if (!(event_name in events)) {
                    events[event_name] = [];
                }
                events[event_name].push(callback);
            }
        );
        this.ClearEvent = Polymorphic.Create(
            [String],
            function(event_name) {
                events[event_name] = [];
            }
        );
        this.TriggerEvent = Polymorphic.Create(
            [String, Array],
            function(event_name, parameters) {
                if (!(event_name in events)) {
                    return;
                }
                var out = this;
                events[event_name].forEach(function(callback) {
                    callback.apply(out, parameters);
                });
            }
        );
    }

    //  Export public APIs / classes.
    Namespace.Export(ns, "BaseObject", BaseObject);
});